home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / readers / nn-tk.001 / nn-tk~ / nn / term.c < prev    next >
C/C++ Source or Header  |  1996-03-30  |  47KB  |  2,507 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Terminal interface.
  5.  */
  6. #define raw __curses__raw__
  7. #include <signal.h>
  8. #include <errno.h>
  9. #include "config.h"
  10. #include "keymap.h"
  11. #include "regexp.h"
  12. #include "nn_term.h"
  13.  
  14. #ifdef TK
  15. #undef RESIZING
  16. #endif /*TK*/
  17.  
  18. #ifdef RESIZING
  19. #include <sys/ioctl.h>            /* for TIOCGWINSZ */
  20.  
  21. #ifdef SYSV_RESIZING
  22. #include <sys/stream.h>
  23. #include <sys/ptem.h>
  24. #endif    /* SYSV_RESIZING */
  25.  
  26. extern int s_resized;
  27. #endif    /* RESIZING */
  28.  
  29. #ifdef FAKE_INTERRUPT
  30. #include <setjmp.h>
  31. #endif
  32.  
  33. #ifdef HAVE_TERMIOS
  34. #include <termios.h>
  35. #endif
  36.  
  37. #ifdef USE_TERMINFO
  38. # ifdef HPUX80
  39. # include <termio.h>
  40. # endif /* HPUX80 */
  41. # include <curses.h>
  42. # ifndef VINTR
  43. #  include <termio.h>    /* some systems don't include this in curses.h */
  44. # endif /* VINTR */
  45. # ifndef auto_left_margin
  46. #  include <term.h>
  47. # endif    /* !auto_left_margin */
  48. #else
  49. #define USE_TERMCAP
  50. #ifdef __FreeBSD__
  51. #include <termcap.h>
  52. #endif
  53. #endif
  54.  
  55. #ifdef HAVE_TERMIO
  56. # ifdef USE_TERMCAP
  57. #  include <termio.h>
  58. # endif    /* USE_TERMCAP */
  59. #else
  60. #ifndef HAVE_TERMIOS
  61. # include <sgtty.h>
  62. #endif
  63. #endif
  64.  
  65. /* SYSV curses.h clash */
  66. #undef raw
  67.  
  68. /* term.c */
  69.  
  70. #ifdef __STDC__
  71. static int outc __APROTO((char c));
  72. #else
  73. static int outc __APROTO(());
  74. #endif
  75. static void set_term_speed __APROTO((register unsigned long sp));
  76. static void raw_not_ok_error __APROTO((void));
  77. static sig_type rd_timeout __APROTO((int n));
  78. static int read_char_kbd __APROTO((int tmo));
  79. static void unread_char __APROTO((int c));
  80.  
  81. static sig_type catch_winch();
  82.  
  83. import int data_bits;
  84. import int batch_mode;
  85. import char *help_directory;
  86.  
  87. extern void ding();
  88. extern void clrmsg();
  89. extern void gotoxy();
  90.  
  91. struct msg_list {
  92.     char *buf;
  93.     struct msg_list *prev;
  94. };
  95. static struct msg_list *msg_stack = NULL, *msg_ptr = NULL;
  96.  
  97. export int  message_history = 15;
  98. export char *term_name = NULL;
  99. export int  show_current_time = 1;
  100. export int  conf_dont_sleep = 0;
  101. export int  prompt_length;
  102. export int  terminal_speed = 0;
  103. export int  slow_speed = 1200;
  104. export int  any_message = 0;
  105. export int  flow_control = 1;
  106. export int  use_visible_bell = 1; /* if supported by terminal */
  107. export int  ignore_xon_xoff = 1;
  108. export int  multi_key_guard_time = 2; /* tenths of a second */
  109. export int  guard_double_slash = 0; /* need /// or //+ to clear line */
  110. export char *shade_on_attr = NULL;
  111. export char *shade_off_attr = NULL;
  112. export int  mouse_state; /* if xterm is in mouse state */
  113. export int  mouse_usage;  /* 0 don't set mouse, 1 only if xterm,
  114.                 2 set mouse */
  115.  
  116. export key_type help_key = '?';
  117. export key_type comp1_key = SP;
  118. export key_type comp2_key = TAB;
  119. export key_type erase_key, kill_key;
  120. export key_type delword_key = CONTROL_('W');
  121.  
  122. static char bell_str[256] = "\007";
  123. static appl_keypad_mode = 0;
  124.  
  125. #ifdef USE_TERMINFO
  126.  
  127. #define HAS_CAP(str) (str && *str)
  128.  
  129. extern char *tgoto();        /* some systems don't have this in term.h */
  130.  
  131. #else
  132.  
  133. char *tgoto();
  134. char PC;
  135. char *BC, *UP;
  136. short ospeed;
  137.  
  138. static char XBC[64], XUP[64];
  139. static char enter_ca_mode[64], exit_ca_mode[64];
  140. static char cursor_home[64];
  141. static char cursor_address[128];
  142. static char clear_screen[64];
  143. static char clr_eol[64];
  144. static char clr_eos[64];
  145. static char enter_standout_mode[64], exit_standout_mode[64];
  146. static char enter_underline_mode[64], exit_underline_mode[64];
  147. static char key_down[64], key_up[64], key_right[64], key_left[64];
  148. static char keypad_local[64], keypad_xmit[64];
  149.  
  150. int  magic_cookie_glitch;    /* magic cookie size */
  151. int  ceol_standout_glitch;    /* hp brain damage! */
  152. int  auto_right_margin;        /* automatic right margin */
  153. int  eat_newline_glitch;    /* newline ignored at right margin */
  154.  
  155. #define putp(str)    tputs(str, 1, outc)
  156.  
  157. #define HAS_CAP(str)    (*str)
  158.  
  159. #endif    /* USE_TERMCAP */
  160.  
  161. static char key_mouse_d1[64] = "\33[M ";
  162. static char key_mouse_d2[64] = "\33[M!";
  163. static char key_mouse_d3[64] = "\33[M\"";
  164. static char key_mouse_u1[64] = "\33[M#";
  165.  
  166. /*
  167.  * Compute the greatest multiple of p not greater than x.
  168.  * p must be a power of 2.
  169.  * x must be nonnegative, for portability to non-2's-complement hosts.
  170.  */    
  171. #define DISCARD_REMAINDER(x,p) ((x) & ~((p)-1))
  172.  
  173. #ifdef __STDC__
  174. static int
  175. outc(char c)
  176. #else
  177. static int
  178. outc(c) char c;
  179. #endif
  180. {
  181. #ifndef TK
  182.     putchar(c);
  183. #endif
  184.     return 0;            /* XXX What is it supposed to return? */
  185. }
  186.  
  187.  
  188. #ifdef BROKEN_TPUTS
  189. /* tputs is broken on UNISYS I've been told */
  190. #define putpc(str, cnt)    tputs(str, 0, outc)
  191. #else
  192. #define putpc(str, cnt)    tputs(str, cnt, outc)
  193. #endif
  194.  
  195. int  Lines, Columns;    /* screen size */
  196. int  cookie_size;    /* size of magic cookie */
  197. int  two_cookies;    /* space needed to enter&exit standout mode */
  198. int  STANDOUT;        /* terminal got standout mode */
  199.  
  200. int curxy_c = 0, curxy_l = -1;
  201. static int savxy_c = 0, savxy_l = -1;
  202. static int just_sent_cr = 0;    /* just sent \r to avoid 'xn' term attribute */
  203.  
  204. static int *nonsp;    /* number of non-space characters on line */
  205.  
  206. #ifdef TERM_DEBUG
  207. static char *term_debug = NULL;
  208. extern char *getenv();
  209. #define curxy_nonsp    (curxy_l < 0 ? -1 : nonsp[curxy_l])
  210. #endif
  211.  
  212. #ifdef FAKE_INTERRUPT
  213.  
  214. extern jmp_buf fake_keyb_sig;
  215. extern int arm_fake_keyb_sig;
  216. extern char fake_keyb_siglist[];
  217. #endif    /* FAKE_INTERRUPT */
  218.  
  219. #if defined(HAVE_TERMIO) || defined(HAVE_TERMIOS)
  220.  
  221. /* This used to be 50, but there are some rather complex bugs in the SYSV */
  222. /* TERMIO driver... */
  223. #define KEY_BURST 10    /* read bursts of 1 char (or timeout after 100 ms) */
  224.  
  225. #undef CBREAK
  226.  
  227. #ifdef HAVE_TERMIOS
  228. static struct termios norm_tty, raw_tty;
  229. #else
  230. static struct termio norm_tty, raw_tty;
  231. #endif
  232.  
  233. #define    IntrC    ((key_type) norm_tty.c_cc[VINTR])
  234. #define    EraseC    ((key_type) norm_tty.c_cc[VERASE])
  235. #define KillC    ((key_type) norm_tty.c_cc[VKILL])
  236. #ifdef HAVE_TERMIOS
  237. #define SuspC   ((key_type) norm_tty.c_cc[VSUSP])
  238. #else
  239. #define SuspC    ((key_type) CONTROL_('Z'))    /* norm_tty.c_cc[SWTCH] */
  240. #endif
  241.  
  242. #else    /* V7/BSD TTY DRIVER */
  243.  
  244. static struct sgttyb norm_tty, raw_tty;
  245. static struct tchars norm_chars;
  246.  
  247. #define    IntrC    ((key_type) norm_chars.t_intrc)
  248. #define    EraseC    ((key_type) norm_tty.sg_erase)
  249. #define KillC    ((key_type) norm_tty.sg_kill)
  250.  
  251. #ifdef TIOCGLTC
  252. static struct     ltchars spec_chars;
  253. #define SuspC    ((key_type) spec_chars.t_suspc)
  254. #else
  255. #define    SuspC    ((key_type) CONTROL_('Z'))
  256. #endif
  257.  
  258. #endif
  259.  
  260. #ifdef USE_TERMCAP
  261.  
  262. opt_cap(cap, buf)
  263. char *cap, *buf;
  264. {
  265.     char *tgetstr();
  266.  
  267.     *buf = NUL;
  268.     return tgetstr(cap, &buf) != NULL;
  269. }
  270.  
  271. get_cap(cap, buf)
  272. char *cap, *buf;
  273. {
  274.     if (!opt_cap(cap, buf))
  275.     nn_exitmsg(1, "TERMCAP entry for %s has no '%s' capability",
  276.            term_name, cap);
  277. }
  278.  
  279. #endif  /* USE_TERMCAP */
  280.  
  281. /*
  282.  * timeout in n/10 seconds via SIGALRM
  283.  */
  284.  
  285. void micro_alarm(n)
  286. int n;
  287. {
  288. #ifdef HAVE_UALARM
  289.     ualarm(n<=1 ? 100000 : n*100000, 0); /* 4.3 BSD ualarm() */
  290. #else
  291. #ifdef MICRO_ALARM
  292.     if (n <= 0) n = 1;
  293.     MICRO_ALARM(n);            /* System specific timeout */
  294. #else
  295.     alarm(n <= 10 ? 1 : (n+9)/10);    /* Standard alarm() call */
  296. #endif    /* MICRO_ALARM */
  297. #endif    /* HAVE_UALARM */
  298. }
  299.  
  300. static int multi_keys = 0;
  301.  
  302. static struct multi_key {
  303.     key_type *cur_key;
  304.     key_type *keys;
  305.     key_type code;
  306. } multi_key_list[MULTI_KEYS];
  307.  
  308. void enter_multi_key(code, keys)
  309. int code;
  310. key_type *keys;
  311. {
  312.     register i;
  313.  
  314.     if (strlen((char *)keys) == 1)
  315.     /* will ignore arrow keys overlaying these keys */
  316.     if (*keys == NL || *keys == CR ||
  317.         *keys == erase_key || *keys == kill_key ||
  318.         *keys == IntrC) return;
  319.  
  320.     /* lookup code to see if it is already defined... */
  321.     for (i = 0; i < multi_keys; i++)
  322.     if (multi_key_list[i].code == (key_type)code)
  323.         goto replace_key;
  324.  
  325.     i = multi_keys++;
  326.  
  327.     /* now i points to matching or empty slot */
  328.     if (i >= MULTI_KEYS) {
  329.     /* should never happen */
  330.     log_entry('E', "too many multi keys");
  331.     return;
  332.     }
  333.  
  334.  replace_key:
  335.  
  336.     multi_key_list[i].keys = keys;
  337.     multi_key_list[i].code = code;
  338. }
  339.  
  340. void dump_multi_keys()
  341. {
  342.     register i;
  343.     register key_type *cp;
  344.  
  345.     clrdisp();
  346.     tkb_clear();
  347.     tk("display_Make");
  348.     pg_init(0, 1);
  349.  
  350.     for (i = 0; i < multi_keys; i++) {
  351.     if (pg_next() < 0) break;
  352.     tkb_tprintf("%d\t%s\t", i, key_name(multi_key_list[i].code));
  353.     for (cp = multi_key_list[i].keys; *cp; cp++)
  354.         tkb_tprintf(" %s", key_name(*cp));
  355.     tkb_c('\n');
  356.     tkb_display();
  357.     }
  358.  
  359.     pg_end();
  360. }
  361.  
  362.  
  363. #ifdef RESIZING
  364.  
  365. static sig_type catch_winch(n)
  366. int n;
  367. {
  368.     struct winsize winsize;
  369.     int i;
  370.  
  371.     (void) signal(SIGWINCH, catch_winch);
  372.     if (ioctl(0, TIOCGWINSZ, &winsize) >= 0
  373.     && (winsize.ws_row != Lines || winsize.ws_col != Columns)) {
  374. #ifndef TK
  375.     nonsp = resizeobj(nonsp, int, winsize.ws_row);
  376.     if ((int)winsize.ws_row > Lines)
  377.         for (i = Lines; i < (int)winsize.ws_row; i++) nonsp[i] = winsize.ws_col;
  378.     if ((int)winsize.ws_col < Columns)
  379.         for (i = 0; i < (int)winsize.ws_row; i++)
  380.         if (nonsp[i] > (int)winsize.ws_col) nonsp[i] = winsize.ws_col;
  381. #endif
  382.     Lines = winsize.ws_row;
  383.     Columns = winsize.ws_col;
  384.     curxy_l = -1;
  385.     s_redraw = 1;
  386.     s_resized = 1;
  387.     }
  388. #ifdef FAKE_INTERRUPT
  389.     if (fake_keyb_siglist[n] && arm_fake_keyb_sig)
  390.     longjmp(fake_keyb_sig, 1);
  391. #endif    /* FAKE_INTERRUPT */
  392. }
  393. #endif /* RESIZING */
  394.  
  395. #ifdef SV_INTERRUPT
  396. #ifdef NO_SIGINTERRUPT
  397. static siginterrupt(signo, on)
  398. {
  399.   struct sigvec sv;
  400.   sv.sv_handler = signal (signo, SIG_DFL);
  401.   sv.sv_mask = 0;
  402.   sv.sv_flags = on ? SV_INTERRUPT : 0;
  403.   sigvec (signo, &sv, 0);
  404. }
  405. #endif    /* NO_SIGINTERRUPT */
  406. #endif    /* SV_INTERRUPT */
  407.  
  408. #ifdef FAKE_INTERRUPT
  409. #define SV_INTERRUPT
  410. static siginterrupt (signo, on)
  411. {
  412.     fake_keyb_siglist[signo] = on;
  413. }
  414. #endif    /* FAKE_INTERRUPT */
  415.  
  416. static unsigned sp_table[] = {
  417. #ifdef B115200
  418.     B115200, 11520,
  419. #endif
  420. #ifdef B57600
  421.     B57600, 5760,
  422. #endif
  423.     B9600, 960,
  424. #ifdef B19200
  425.     B19200, 1920,
  426. #else
  427. #ifdef EXTA
  428.     EXTA, 1920,
  429. #endif    /* EXTA */
  430. #endif    /* B19200 */
  431. #ifdef B38400
  432.     B38400, 3840,
  433. #else
  434. #ifdef EXTB
  435.     EXTB, 3840,
  436. #endif    /* EXTB */
  437. #endif    /* B38400 */
  438.     B1200, 120,
  439.     B2400, 240,
  440.     B4800, 480,
  441.     B300,   30,
  442.     0,    0
  443. };
  444.  
  445. static  void set_term_speed(sp)
  446. register unsigned long sp;
  447. {
  448.     register unsigned *tp;
  449.  
  450.     for (tp = sp_table; *tp; tp += 2)
  451.     if (*tp == sp) {
  452.         terminal_speed = tp[1];
  453.         return;
  454.     }
  455.  
  456.     terminal_speed = 30;
  457. }
  458.  
  459. static void raw_not_ok_error()
  460. {
  461.     if (batch_mode) return;
  462.     nn_exitmsg(1, "Not prepared for terminal i/o");
  463.     /*NOTREACHED*/
  464. }
  465.  
  466.  
  467. #define    RAW_CHECK    if (terminal_speed == 0) {raw_not_ok_error(); return 0;}
  468. #define    RAW_CHECK_V    if (terminal_speed == 0) {raw_not_ok_error(); return;}
  469. #define BATCH_CHECK    if (terminal_speed == 0) return 0
  470. #define BATCH_CHECK_V    if (terminal_speed == 0) return
  471.  
  472. void init_term(full)
  473. int full;
  474. {
  475. #ifndef TK
  476. #ifdef USE_TERMCAP
  477.     char tbuf[1024];
  478. #endif
  479.     int i;
  480.  
  481. #ifdef TERM_DEBUG
  482.     term_debug = getenv("TERM_DEBUG");
  483.     if (term_debug) fprintf (stderr, "init_term(%d)\n", full);
  484. #endif
  485.  
  486.     if (batch_mode) {
  487.     term_name = "batch";
  488.     close(0);
  489.     open("/dev/null", 0);
  490.     STANDOUT = 0;
  491.     cookie_size = 1;
  492.     return;
  493.     }
  494.  
  495.     if ((term_name = getenv("TERM")) == NULL) {
  496.     if (full)
  497.         nn_exitmsg(1, "No TERM variable in environment");
  498.     else
  499.         term_name = "unknown";
  500.     }
  501.  
  502.     if (!full)
  503.     return;
  504.  
  505. #ifdef HAVE_TERMIO
  506.     ioctl(0, TCGETA, &norm_tty);
  507. #else
  508. #ifdef HAVE_TERMIOS
  509.     tcgetattr(0, &norm_tty);
  510. #else
  511.     ioctl(0, TIOCGETP, &norm_tty);
  512. #endif
  513. #endif    /* HAVE_TERMIO */
  514.  
  515. #ifdef USE_TERMINFO
  516.     setupterm((char *)NULL, 1, (int *)NULL);
  517.     Columns = columns;
  518.     Lines = lines;
  519.     if (use_visible_bell && HAS_CAP(flash_screen))
  520.     strcpy(bell_str, flash_screen);
  521.     else if (HAS_CAP(bell))
  522.     strcpy(bell_str, bell);
  523.     if (! HAS_CAP(cursor_home))
  524.     cursor_home = copy_str(tgoto(cursor_address, 0, 0));
  525. #else
  526.  
  527.     if (tgetent(tbuf, term_name) <= 0)
  528.     nn_exitmsg(1, "Unknown terminal type: %s", term_name);
  529.  
  530.     if (opt_cap("bc", XBC)) BC = XBC;
  531.     if (opt_cap("up", XUP)) UP = XUP;
  532.     opt_cap("pc", cursor_address);    /* temp. usage */
  533.     PC = cursor_address[0];
  534.  
  535.     get_cap("cm", cursor_address);
  536.     if (!opt_cap("ho", cursor_home))
  537.     strcpy(cursor_home, tgoto(cursor_address, 0, 0));
  538.  
  539.     get_cap("cl", clear_screen);
  540.     opt_cap("ce", clr_eol);
  541.     opt_cap("cd", clr_eos);
  542.  
  543.     Lines = tgetnum("li");
  544.     Columns = tgetnum("co");
  545.  
  546.     opt_cap("so", enter_standout_mode);
  547.     opt_cap("se", exit_standout_mode);
  548.  
  549.     opt_cap("us", enter_underline_mode);
  550.     opt_cap("ue", exit_underline_mode);
  551.  
  552.     opt_cap("kd", key_down);
  553.     opt_cap("ku", key_up);
  554.     opt_cap("kr", key_right);
  555.     opt_cap("kl", key_left);
  556.  
  557.     magic_cookie_glitch = tgetnum("sg");
  558.  
  559.     ceol_standout_glitch = tgetflag("xs");
  560.     auto_right_margin = tgetflag("am");
  561.     eat_newline_glitch = tgetflag("xn");
  562.  
  563.     opt_cap("ti", enter_ca_mode);
  564.     opt_cap("te", exit_ca_mode);
  565.     opt_cap("ks", keypad_xmit);        /* used to turn "application cursor */
  566.     opt_cap("ke", keypad_local);    /* key" mode on and off (sometimes) */
  567.  
  568.     if (!use_visible_bell || !opt_cap("vb", bell_str))
  569.     if (!opt_cap("bl", bell_str))
  570.         strcpy(bell_str, "\007");
  571.  
  572. #endif /* USE_TERMINFO */
  573.  
  574. #ifdef RESIZING
  575.     {
  576.     struct winsize winsize;
  577.  
  578.     if (ioctl(0, TIOCGWINSZ, &winsize) >= 0
  579.         && winsize.ws_row != 0 && winsize.ws_col != 0) {
  580.         Lines = winsize.ws_row;
  581.         Columns = winsize.ws_col;
  582.         (void) signal(SIGWINCH, catch_winch);
  583. #ifdef SV_INTERRUPT
  584.         siginterrupt(SIGWINCH, 1);    /* make read from tty interruptable */
  585. #endif /* SV_INTERRUPT */
  586.     }
  587.     }
  588. #endif /* RESIZING */
  589.  
  590.     /* Stop NN from blowing up if on a *really* dumb terminal, like "dumb" */
  591.     if (Lines < 1)
  592.       Lines = 24;
  593.     if (Columns < 1)
  594.       Columns = 80;
  595.  
  596.     nonsp = newobj(int, Lines);
  597.     for (i = 0; i < Lines; i++) nonsp[i] = Columns;
  598.     
  599.     STANDOUT = HAS_CAP(enter_standout_mode);
  600.     cookie_size = magic_cookie_glitch;
  601.     if (STANDOUT) {
  602.     if (cookie_size < 0) cookie_size = 0;
  603.     two_cookies = 2 * cookie_size;
  604.     } else
  605.     cookie_size = two_cookies = 0;
  606.  
  607.     raw_tty = norm_tty;
  608.  
  609. #ifdef HAVE_TERMIO
  610.     raw_tty.c_iflag &= ~(BRKINT|INLCR|ICRNL|IGNCR|ISTRIP);
  611.     raw_tty.c_iflag |= IGNBRK|IGNPAR;
  612.     raw_tty.c_oflag &= ~OPOST;
  613.     raw_tty.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|NOFLSH);
  614.  
  615.     /* read a maximum of 10 characters in one burst; timeout in 1-200 ms */
  616.     raw_tty.c_cc[VMIN] = KEY_BURST;
  617.     raw_tty.c_cc[VTIME] = ((int)(raw_tty.c_cflag & CBAUD) > B1200) ? 1 : 2;
  618.     set_term_speed((unsigned long)(raw_tty.c_cflag & CBAUD));
  619. #else
  620. #ifdef HAVE_TERMIOS
  621.     cfmakeraw(&raw_tty);
  622.     /* read a maximum of 10 characters in one burst; timeout in 1-200 ms */
  623.     raw_tty.c_cc[VMIN] = KEY_BURST;
  624.     raw_tty.c_cc[VTIME] = (cfgetispeed(&raw_tty) > B1200) ? 1 : 2;
  625.     set_term_speed((unsigned long)cfgetospeed(&raw_tty));
  626. #ifdef SV_INTERRUPT
  627.     siginterrupt(SIGTSTP, 1);
  628.     siginterrupt(SIGALRM, 1);
  629. #endif    /* SV_INTERRUPT */
  630. #else
  631.     ioctl(0, TIOCGETC, &norm_chars);
  632.  
  633. #ifdef TIOCGLTC
  634.     ioctl(0, TIOCGLTC, &spec_chars);
  635. #endif    /* TIOCGLTC */
  636.  
  637.     ospeed = norm_tty.sg_ospeed;
  638.     set_term_speed((unsigned long)ospeed);
  639.  
  640.     raw_tty.sg_flags &= ~(ECHO | CRMOD);
  641. #ifdef CBREAK
  642. #ifdef SV_INTERRUPT            /* make read from tty interruptable */
  643.     siginterrupt(SIGTSTP, 1);        /* this is necessary to redraw screen */
  644. #endif    /* SV_INTERRUPT */
  645.     raw_tty.sg_flags |= CBREAK;
  646. #else
  647.     raw_tty.sg_flags |= RAW;
  648. #endif    /* CBREAK */
  649.  
  650. #ifdef SV_INTERRUPT
  651.     siginterrupt(SIGALRM, 1);        /* make read from tty interruptable */
  652. #endif    /* SV_INTERRUPT */
  653. #endif
  654. #endif    /* HAVE_TERMIO */
  655.  
  656.     erase_key = EraseC;
  657.     kill_key  = KillC;
  658.  
  659.     if (HAS_CAP(key_down))
  660.     enter_multi_key(K_down_arrow, (key_type *)key_down);
  661.     if (HAS_CAP(key_up))
  662.     enter_multi_key(K_up_arrow, (key_type *)key_up);
  663.     if (HAS_CAP(key_right))
  664.     enter_multi_key(K_right_arrow, (key_type *)key_right);
  665.     if (HAS_CAP(key_left))
  666.     enter_multi_key(K_left_arrow, (key_type *)key_left);
  667.  
  668.     enter_multi_key(K_m_d1, (key_type *)key_mouse_d1);
  669.     enter_multi_key(K_m_d2, (key_type *)key_mouse_d2);
  670.     enter_multi_key(K_m_d3, (key_type *)key_mouse_d3);
  671.     enter_multi_key(K_m_u1, (key_type *)key_mouse_u1);
  672.  
  673.     appl_keypad_mode = (HAS_CAP(keypad_xmit) && HAS_CAP(keypad_local));
  674.     if (!HAS_CAP(key_up)) appl_keypad_mode = 0;    /* no cursor keys */
  675.     if (appl_keypad_mode) {
  676.     /* Use of ks/ke isn't consistent, so we must guess what to do. */
  677.     /* If termcap expects keys to send ESC [, don't switch */
  678.     appl_keypad_mode = (key_up[0] != '\033' || key_up[1] != '[');
  679.     }
  680.     if ((mouse_usage == 2) || ((mouse_usage == 1) 
  681.                     && !strncmp("xterm",term_name,5))) {
  682.     mouse_state = 1;
  683.     flow_control = 0;
  684.     } else {
  685.     mouse_state = 0;
  686.     }
  687.     visual_on();
  688. #else /* TK */
  689.     Columns=120;
  690.     terminal_speed=100000;
  691.     erase_key = 127;
  692. #endif /* TK */
  693. }
  694.  
  695. void
  696. home()
  697. {
  698.     BATCH_CHECK_V;
  699.  
  700. #ifdef TERM_DEBUG
  701.     if (term_debug) fprintf(stderr, "home\n");
  702. #endif
  703. #ifndef TK
  704.     putp(cursor_home);
  705. #endif /* TK */
  706.     curxy_c = curxy_l = 0;
  707. }
  708.  
  709. void
  710. save_xy()
  711. {
  712.     savxy_c = curxy_c; savxy_l = curxy_l;
  713. }
  714.  
  715. void
  716. restore_xy()
  717. {
  718.     if (savxy_l < 0) return;
  719.     gotoxy(savxy_c, savxy_l); fl;
  720. }
  721.  
  722. void 
  723. gotoxy(c, l)
  724. int c, l;
  725. {
  726.     BATCH_CHECK_V;
  727.  
  728. #ifdef TERM_DEBUG
  729.     if (term_debug)
  730.     fprintf(stderr, "gotoxy %d %d -> %d %d\n", curxy_c, curxy_l, c, l);
  731. #endif
  732. #ifndef TK
  733.     if (Columns <= (unsigned)c || Lines <= (unsigned)l)
  734.     return;
  735.  
  736.     if (!(c | l))
  737.     putp(cursor_home);
  738.     else
  739.         putp(tgoto(cursor_address, c, l));
  740. #endif /* TK */
  741. ;   curxy_c = c; curxy_l = l;
  742. }
  743.  
  744. void
  745. clrdisp()
  746. {
  747.     int i;
  748.  
  749.     BATCH_CHECK_V;
  750.  
  751. #ifndef TK
  752. #ifdef TERM_DEBUG
  753.     if (term_debug) fprintf(stderr, "clrdisp\n");
  754. #endif
  755.  
  756.     putpc(clear_screen, Lines);
  757.     curxy_c = curxy_l = 0;
  758.     savxy_l = -1;
  759.     for (i = 0; i < Lines; i++) nonsp[i] = 0;
  760.     msg_ptr = msg_stack;
  761. #endif
  762. }
  763.  
  764. void     clrline_noflush();
  765.  
  766. void
  767. tclrline()
  768. {
  769.     BATCH_CHECK_V;
  770.  
  771.     /* If we moved the cursor left to avoid weird effects, don't clear. */
  772.     if (just_sent_cr)
  773.     return;
  774.  
  775.     clrline_noflush();
  776.     fl;
  777. }
  778.  
  779. void
  780. clrline()
  781. {
  782.     tk_clrline();
  783.     tclrline();
  784. }
  785.  
  786. void
  787. clrline_noflush()
  788. {
  789.     int oldxy_c, oldxy_l, spcnt;
  790.  
  791.     BATCH_CHECK_V;
  792.  
  793. #ifdef TERM_DEBUG
  794.     if (term_debug)
  795.     fprintf(stderr, "clrline %d %d [%d]",curxy_c, curxy_l, curxy_nonsp);
  796. #endif
  797.  
  798.     if (curxy_l < 0)
  799.     return;
  800.  
  801.     /* remainder of line already blank? */
  802.  
  803. #ifndef TK
  804.     if (curxy_c >= nonsp[curxy_l]) {
  805. #ifdef TERM_DEBUG
  806.     if (term_debug) fprintf(stderr, " ignored\n");
  807. #endif
  808.         return;
  809.     }
  810.  
  811.     if (HAS_CAP(clr_eol)) {
  812. #ifdef TERM_DEBUG
  813.         if (term_debug) fprintf(stderr, "\n");
  814. #endif
  815.         putp(clr_eol);
  816.     } else {
  817.     oldxy_c = curxy_c; oldxy_l = curxy_l;
  818.  
  819.     spcnt = nonsp[curxy_l] - curxy_c;
  820.  
  821.     /* guard against scroll */
  822.  
  823.     if (auto_right_margin && curxy_l == Lines-1 && curxy_c+spcnt == Columns)
  824.         spcnt--;
  825.  
  826. #ifdef TERM_DEBUG
  827.     if (term_debug) fprintf(stderr," %d\n", spcnt);
  828. #endif /* TERM_DEBUG */
  829.  
  830. #ifdef TERM_DEBUG
  831.     if (term_debug && *term_debug) {
  832.         while (spcnt--) ttputc(*term_debug);
  833.           spcnt = 0;
  834.     }
  835. #endif
  836.     /* clear out line */
  837.  
  838.     while (spcnt--) ttputc(SP);
  839.  
  840.     if (curxy_c != oldxy_c || curxy_l != oldxy_l)
  841.         gotoxy(oldxy_c, oldxy_l);
  842.     }
  843.     nonsp[curxy_l] = curxy_c;
  844. #endif /* TK */
  845. }
  846.  
  847. void
  848. clrpage()
  849. {
  850.     int oldxy_c, oldxy_l, i;
  851.  
  852.     BATCH_CHECK_V;
  853.  
  854. #ifdef TERM_DEBUG
  855.     if (term_debug)
  856.     fprintf(stderr, "clrpage %d %d [%d]\n", curxy_c, curxy_l, curxy_nonsp);
  857. #endif
  858. #ifndef TK
  859.     if (curxy_l < 0)
  860.     return;
  861.  
  862.     oldxy_c = curxy_c; oldxy_l = curxy_l;
  863.  
  864.     /* code below only handles curxy_c == 0 */
  865.  
  866.     if (curxy_c != 0) {
  867.     clrline();
  868.     if (curxy_l < Lines-1) gotoxy(0, curxy_l+1);
  869.     }
  870.  
  871.     /* clear to end of screen */
  872.  
  873.     if (curxy_c == 0) {
  874.         if (HAS_CAP(clr_eos)) {
  875.         putpc(clr_eos, Lines - curxy_l);
  876.         for (i = curxy_l; i < Lines; i++) nonsp[i] = 0;
  877.         } else if (curxy_l == 0) {
  878.         putpc(clear_screen, Lines);
  879.         for (i = 0; i < Lines; i++) nonsp[i] = 0;
  880.         } else {
  881.         for (i = curxy_l; i < Lines; i++) {
  882.         if (nonsp[i] != 0) {
  883.             gotoxy(0, i);
  884.                     clrline_noflush();
  885.         }
  886.         }
  887.     }
  888.     }
  889.  
  890.     if (curxy_c != oldxy_c || curxy_l != oldxy_l)
  891.     gotoxy(oldxy_c, oldxy_l);
  892.  
  893.     fl;
  894.     msg_ptr = msg_stack;
  895. #endif /* TK */
  896. }
  897.  
  898. static char buf[512];
  899.  
  900. /*VARARGS*/
  901. void ttprintf(va_alist)
  902. va_dcl
  903. {
  904.     use_vararg;
  905.  
  906.     start_vararg;
  907.     tvprintf(va_args1toN);
  908.     end_vararg;
  909. }
  910.  
  911. void tprintf(va_alist)
  912. va_dcl
  913. {
  914.     char buff[300];
  915.     char *fmt;
  916.     use_vararg;
  917.  
  918.     start_vararg;
  919.     fmt = va_arg1(char *);
  920.     vsprintf(buff, fmt, va_args2toN);
  921.     tk_txt_a(buff);
  922.     end_vararg;
  923.     start_vararg;
  924.     tvprintf(va_args1toN);
  925.     end_vararg;
  926. }
  927.  
  928. void tvprintf(va_tail)
  929. va_tdcl
  930. {
  931.     char *fmt, *str;
  932.  
  933.     fmt = va_arg1(char *);
  934.     vsprintf(buf, fmt, va_args2toN);
  935.  
  936.     for (str = buf; *str; str++)
  937.         ttputc(*str);
  938. }
  939.  
  940. void tputc(c)
  941. int c;
  942. {
  943.    ttputc(c);
  944.    tk_txt_c(c);
  945. }
  946.  
  947. void ttputc(c)
  948. int c;
  949. {
  950.     int i;
  951.  
  952. #ifdef TERM_DEBUG
  953.     if (term_debug) {
  954.     fprintf (stderr, "tputc %d %d [%d] ", curxy_c, curxy_l, curxy_nonsp);
  955.     if (c < ' ' || c > '~')
  956.     else
  957.         fprintf(stderr, "'%c'", c);
  958.     }
  959. #endif
  960.     just_sent_cr = 0;
  961. #ifndef TK
  962.     putchar(c);
  963. #endif /* TK */
  964.     switch (c) {
  965.  
  966.     case '\n':
  967.     curxy_c = 0;
  968.     if (curxy_l >= 0) curxy_l++;
  969.     break;
  970.  
  971.     case '\r':
  972.     curxy_c = 0;
  973.         break;
  974.  
  975.     case '\t':
  976.     curxy_c = DISCARD_REMAINDER(curxy_c + 8, 8);
  977.      break;
  978.  
  979.     case '\b':
  980.     curxy_c--;
  981.     break;
  982.  
  983.     case ' ':
  984.     curxy_c++;
  985. #ifndef TK
  986.     if (curxy_l >= 0 && nonsp[curxy_l] == curxy_c)
  987.         nonsp[curxy_l]--;
  988. #endif /* TK */
  989.     break;
  990.  
  991.     default:
  992.     curxy_c++;
  993. #ifndef TK
  994.     if (curxy_l >= 0 && nonsp[curxy_l] < curxy_c)
  995.          nonsp[curxy_l] = curxy_c;
  996. #endif /* TK */
  997.     break;
  998.        
  999.     }
  1000.  
  1001. #ifdef TERM_DEBUG
  1002.     if (term_debug)
  1003.     fprintf(stderr, " -> %d %d [%d]",curxy_c,curxy_l,curxy_nonsp);
  1004. #endif
  1005.  
  1006.     /* account for right margin */
  1007.  
  1008.     if (curxy_c == Columns) {
  1009. #ifdef TERM_DEBUG
  1010.     if (term_debug) fprintf(stderr, " margin");
  1011. #endif
  1012.     if (auto_right_margin) {
  1013.         if (eat_newline_glitch) {
  1014. #ifndef TK
  1015.         putchar(CR);
  1016. #endif /* TK */
  1017.                 just_sent_cr = 1;
  1018.         curxy_c = 0;
  1019.         } else {
  1020.         curxy_c = 0;
  1021.         if (curxy_l >= 0) curxy_l++;
  1022.         }
  1023.     } else
  1024.         curxy_c--;
  1025.     }
  1026.  
  1027.     /* account for vertical scroll */
  1028.  
  1029.     if (curxy_l == Lines) {
  1030. #ifdef TERM_DEBUG
  1031.     if (term_debug) fprintf(stderr, " scroll");
  1032. #endif
  1033. #ifndef TK
  1034.     for (i = 1; i < Lines; i++)
  1035.         nonsp[i-1] = nonsp[i];
  1036.     nonsp[--curxy_l] = 0;
  1037. #endif /* TK */
  1038.     }
  1039.  
  1040. #ifdef TERM_DEBUG
  1041.     if (term_debug) fprintf(stderr, "\n");
  1042. #endif
  1043. }
  1044.  
  1045. static char so_buf[512], *so_p;
  1046. static int so_c, so_l, so_b, so_active = 0;
  1047.  
  1048. int so_gotoxy(c, l, blank)
  1049. int c, l, blank;
  1050. {
  1051.     if (!STANDOUT && c >= 0) {
  1052.     if (c>= 0 && l >= 0) gotoxy(c, l);
  1053.     return 0;
  1054.     }
  1055. #ifndef TK
  1056.     so_active++;
  1057.     so_c = c;
  1058.     so_l = l;
  1059.     so_b = blank;
  1060.     so_p = so_buf;
  1061.     *so_p = NUL;
  1062. #endif
  1063.     return 1;    /* not really true if not standout & c < 0 */
  1064. }
  1065.  
  1066. /*VARARGS*/
  1067. void so_printf(va_alist)
  1068. va_dcl
  1069. {
  1070.     use_vararg;
  1071.  
  1072.     start_vararg;
  1073.     so_vprintf(va_args1toN);
  1074.     end_vararg;
  1075. }
  1076.  
  1077. void so_vprintf(va_tail)
  1078. va_tdcl
  1079. {
  1080.     char *fmt;
  1081. #ifndef TK
  1082.     if (!so_active) {
  1083.     if (ceol_standout_glitch) highlight(0); /* xxx why? */
  1084.     tvprintf(va_args1toN);
  1085.     return;
  1086.     }
  1087.  
  1088.     fmt = va_arg1(char *);
  1089.     vsprintf(so_p, fmt, va_args2toN);
  1090.     while (*so_p) so_p++;
  1091. #endif
  1092. }
  1093.  
  1094. void so_end()
  1095. {
  1096.     int len;
  1097.  
  1098.     if (!so_active) return;
  1099. #ifndef TK
  1100.     if (so_l >= 0) {
  1101.  
  1102.     len = so_p - so_buf + two_cookies;
  1103.  
  1104.     if (so_c < 0)
  1105.         so_c = Columns - len - 2;
  1106.     if (so_c < 0) so_c = 0;
  1107.  
  1108.     if (len + so_c >= Columns) {
  1109.         len = Columns - so_c - two_cookies;
  1110.         so_buf[len] = NUL;
  1111.     }
  1112.  
  1113.     if (cookie_size) {
  1114.         gotoxy(so_c + len - cookie_size, so_l);
  1115.         nn_standout(0);
  1116.     }
  1117.  
  1118.     gotoxy(so_c, so_l);
  1119.  
  1120.     }
  1121.  
  1122.     if ((so_b & 1) && (!STANDOUT || !cookie_size)) ttputc(SP);
  1123.  
  1124.     if (STANDOUT) {
  1125.     if (ceol_standout_glitch) clrline();
  1126.     nn_standout(1);
  1127.     }
  1128.  
  1129.     ttprintf("%s", so_buf);
  1130.  
  1131.     if (STANDOUT) nn_standout(0);
  1132.  
  1133.     if ((so_b & 2) && (!STANDOUT || !cookie_size)) ttputc(SP);
  1134.  
  1135.     so_active = 0;
  1136. #endif
  1137. }
  1138.  
  1139.  
  1140. /*VARARGS*/
  1141. void so_printxy(va_alist)
  1142. va_dcl
  1143. {
  1144.     int c, l;
  1145.     use_vararg;
  1146.  
  1147.     start_vararg;
  1148.  
  1149.     c = va_arg1(int);
  1150.     l = va_arg2(int);
  1151.  
  1152.     so_gotoxy(c, l, 0);
  1153.     so_vprintf(va_args3toN);
  1154.     so_end();
  1155.  
  1156.     end_vararg;
  1157. }
  1158.  
  1159.     
  1160. int underline(on)
  1161. int on;
  1162. {
  1163.     if (cookie_size) return 0;
  1164. #ifdef TERM_DEBUG
  1165.     if (term_debug)
  1166.     fprintf(stderr, "underline %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
  1167. #endif
  1168. #ifndef TK
  1169.     if (! HAS_CAP(enter_underline_mode)) return 0;
  1170.     putp(on ? enter_underline_mode : exit_underline_mode);
  1171. #endif
  1172.     return 1;
  1173. }
  1174.  
  1175. int highlight(on)
  1176. int on;
  1177. {
  1178.     if (cookie_size) return 0;
  1179. #ifdef TERM_DEBUG
  1180.     if (term_debug)
  1181.     fprintf(stderr, "highlight %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
  1182. #endif
  1183. #ifndef TK
  1184.     if (! HAS_CAP(enter_standout_mode)) return 0;
  1185.     putp(on ? enter_standout_mode : exit_standout_mode);
  1186. #endif
  1187.     return 1;
  1188. }
  1189.  
  1190. int shadeline(on)
  1191. int on;
  1192. {
  1193.     if (cookie_size) return 0;
  1194. #ifdef TERM_DEBUG
  1195.     if (term_debug)
  1196.     fprintf(stderr, "shadeline %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
  1197. #endif
  1198. #ifndef TK
  1199.     if (shade_on_attr && shade_off_attr) {
  1200.     putp(on ? shade_on_attr : shade_off_attr);
  1201.     return 1;
  1202.     } else
  1203.     return underline(on);
  1204. #endif
  1205. }
  1206.     
  1207. int nn_standout(on)
  1208. int on;
  1209. {
  1210. #ifdef TERM_DEBUG
  1211.     if (term_debug)
  1212.     fprintf(stderr, "nn_standout %d %d [%d] %d", curxy_c, curxy_l, curxy_nonsp, on);
  1213. #endif
  1214. #ifndef TK
  1215.     if (! HAS_CAP(enter_standout_mode)) return 0;
  1216.     putp(on ? enter_standout_mode : exit_standout_mode);
  1217.     curxy_c += cookie_size;
  1218.     if (curxy_l >= 0 && curxy_c > nonsp[curxy_l])
  1219.     nonsp[curxy_l] = curxy_c;
  1220. #ifdef TERM_DEBUG
  1221.     if (term_debug)
  1222.     fprintf(stderr, " -> %d %d [%d]\n", curxy_c, curxy_l, curxy_nonsp);
  1223. #endif
  1224. #endif
  1225.     return 1;
  1226. }
  1227.  
  1228. static int is_visual = 0;
  1229. static int is_raw = 0;
  1230.  
  1231. #ifdef HAVE_TERMIO
  1232. #define RAW_MODE_ON    ioctl(0, TCSETAW, &raw_tty)
  1233. #define RAW_MODE_OFF   ioctl(0, TCSETAW, &norm_tty)
  1234. #else
  1235. #ifdef HAVE_TERMIOS
  1236. #define RAW_MODE_ON    tcsetattr(0, TCSADRAIN, &raw_tty)
  1237. #define RAW_MODE_OFF   tcsetattr(0, TCSADRAIN, &norm_tty)
  1238. #else
  1239. #define RAW_MODE_ON    ioctl(0, TIOCSETP, &raw_tty)
  1240. #define RAW_MODE_OFF   ioctl(0, TIOCSETP, &norm_tty)
  1241. #endif
  1242. #endif    /* HAVE_TERMIO */
  1243.  
  1244. void
  1245. xterm_mouse_on()
  1246. {
  1247.     putp("\33[?1000h"); 
  1248. }
  1249.  
  1250. void
  1251. xterm_mouse_off()
  1252. {
  1253.     putp("\33[?1000l"); 
  1254. }
  1255.  
  1256. void
  1257. visual_on()
  1258. {
  1259.     BATCH_CHECK_V;
  1260.  
  1261.     if (terminal_speed == 0) return;
  1262.  
  1263. #ifdef TERM_DEBUG
  1264.     if (term_debug) fprintf(stderr, "visual_on\n");
  1265. #endif
  1266. #ifndef TK
  1267.     if (!is_visual) {
  1268.     if (HAS_CAP(enter_ca_mode)) putp(enter_ca_mode);
  1269.     if (appl_keypad_mode) putp(keypad_xmit);
  1270.     if (mouse_state)
  1271.         xterm_mouse_on();
  1272.     fl;
  1273.     }
  1274.     is_visual = 1;
  1275. #endif
  1276. }
  1277.  
  1278. int visual_off()
  1279. {
  1280.     int was_raw = is_raw;
  1281.  
  1282.     if (terminal_speed == 0) return 0;
  1283.  
  1284. #ifdef TERM_DEBUG
  1285.     if (term_debug) fprintf(stderr, "visual_off\n");
  1286. #endif
  1287. #ifndef TK
  1288.     if (is_visual) {
  1289.     if (appl_keypad_mode) putp(keypad_local);
  1290.     if (HAS_CAP(exit_ca_mode)) putp(exit_ca_mode);
  1291.     if (mouse_state)
  1292.         xterm_mouse_off();
  1293.     fl;
  1294.     }
  1295.     is_visual = 0;
  1296.  
  1297.     is_raw = 1;
  1298.     unset_raw();
  1299.  
  1300.     return was_raw;
  1301. #endif
  1302. }
  1303.  
  1304.  
  1305. #ifdef CBREAK
  1306. void
  1307. nn_raw()
  1308. {
  1309. #ifndef TK
  1310.     RAW_CHECK_V;
  1311.  
  1312.     if (is_raw == 1)
  1313.     return;
  1314.     is_raw = 1;
  1315.     RAW_MODE_ON;
  1316. #endif /* TK */
  1317. }
  1318.  
  1319. int
  1320. no_raw()
  1321. {
  1322.     return 0;
  1323. }
  1324.  
  1325. int
  1326. unset_raw()
  1327. {
  1328. #ifndef TK
  1329.     if (is_raw == 0)
  1330.     return 0;
  1331.     RAW_CHECK;
  1332.     RAW_MODE_OFF;
  1333.     is_raw = 0;
  1334. #endif /* TK */
  1335.     return 1;
  1336. }
  1337.  
  1338. #else /* not CBREAK */
  1339. static int must_set_raw = 1;
  1340.  
  1341. #undef raw
  1342. void
  1343. nn_raw()
  1344. {
  1345. #ifndef TK
  1346.     RAW_CHECK_V;
  1347.  
  1348.     if (!flow_control) {
  1349.     if (!must_set_raw) return;
  1350.     must_set_raw = 0;
  1351.     }
  1352.  
  1353.     if (is_raw) return;
  1354.  
  1355.     RAW_MODE_ON;
  1356.     is_raw++;
  1357. #endif /* TK */
  1358. }
  1359.  
  1360. int no_raw()
  1361. {
  1362. #ifndef TK
  1363.     if (!flow_control) return 0;
  1364.  
  1365.     if (!is_raw) return 0;
  1366.  
  1367.     RAW_CHECK;
  1368.  
  1369.     RAW_MODE_OFF;
  1370.  
  1371.     is_raw = 0;
  1372. #endif /* TK  */
  1373.     return 1;
  1374. }
  1375.  
  1376. int unset_raw()
  1377. {
  1378. #ifndef TK
  1379.     int was_raw = is_raw;
  1380.  
  1381.     if (is_raw) {
  1382.     RAW_CHECK;
  1383.     RAW_MODE_OFF;
  1384.     is_raw = 0;
  1385.     }
  1386.  
  1387.     if (!flow_control)
  1388.     must_set_raw = 1;
  1389.     return was_raw;
  1390. #endif /* TK */
  1391. }
  1392.  
  1393. #endif /* CBREAK */
  1394.  
  1395. #ifndef KEY_BURST
  1396. #define KEY_BURST 32
  1397. #endif    /* KEY_BURST */
  1398. #define RD_PUSHBACK 10
  1399. static char rd_buffer[KEY_BURST+RD_PUSHBACK];    /* Holds stuff from read */
  1400. static char *rd_ptr;
  1401. static int rd_count = 0, rd_alarm = 0;
  1402. #ifdef FAKE_INTERRUPT
  1403. static jmp_buf fake_alarm_sig;
  1404. #endif    /* FAKE_INTERRUPT */
  1405.  
  1406. static sig_type rd_timeout(n)
  1407. int n;
  1408. {
  1409.     rd_alarm = 1;
  1410. #ifdef FAKE_INTERRUPT
  1411.     longjmp(fake_alarm_sig, 1);
  1412. #endif    /* FAKE_INTERRUPT */
  1413. }
  1414.  
  1415. #define RD_TIMEOUT    0x1000
  1416. #define RD_INTERRUPT    0x1001
  1417.  
  1418. static int read_char_kbd(tmo)
  1419. int tmo;    /* timeout if no input arrives */
  1420. {
  1421.     if (rd_count <= 0) {
  1422.     if (tmo) {
  1423. #ifdef FAKE_INTERRUPT
  1424.         if (setjmp(fake_alarm_sig)) goto tmout;
  1425. #endif    /* FAKE_INTERRUPT */
  1426.         rd_alarm = 0;
  1427.         signal(SIGALRM, rd_timeout);
  1428.         micro_alarm(multi_key_guard_time);
  1429.     }
  1430.     rd_ptr = rd_buffer + RD_PUSHBACK;
  1431.     rd_count = read(0, rd_ptr, KEY_BURST);
  1432.     if (tmo) {
  1433.         if (rd_alarm) goto tmout;
  1434.         alarm(0);
  1435.     }
  1436.     if (rd_count < 0) {
  1437.         if (errno != EINTR) s_hangup++;
  1438.         return RD_INTERRUPT;
  1439.     }
  1440.     }
  1441.     --rd_count;
  1442.     return *rd_ptr++;
  1443.     
  1444.  tmout:
  1445.     rd_count = 0;
  1446.     return RD_TIMEOUT;
  1447. }
  1448.  
  1449. static void unread_char(c)
  1450. int c;
  1451. {
  1452.     if (rd_ptr == rd_buffer) return;
  1453.     rd_count++;
  1454.     *--rd_ptr = c;
  1455. }
  1456.  
  1457. void
  1458. flush_input()
  1459. {
  1460. #ifndef TK
  1461. #ifndef HAVE_TERMIO
  1462. #ifdef FREAD
  1463.     int arg;
  1464. #endif
  1465. #endif
  1466.  
  1467.     BATCH_CHECK_V;
  1468.  
  1469. #ifdef HAVE_TERMIO
  1470.     ioctl(0, TCFLSH, 0);
  1471. #else
  1472. #ifdef HAVE_TERMIOS
  1473.     tcflush(0, TCIFLUSH);
  1474. #else
  1475. #ifdef FREAD
  1476.     arg = FREAD;
  1477.     ioctl(0, TIOCFLUSH, &arg);
  1478. #else
  1479.     ioctl(0, TIOCFLUSH, 0);
  1480. #endif    /* FREAD */
  1481. #endif
  1482. #endif    /* HAVE_TERMIO */
  1483.     rd_count = 0;
  1484. #endif /* TK */
  1485. }
  1486.  
  1487. int enable_stop = 1;
  1488.  
  1489. int do_macro_processing = 1;
  1490. export int mouse_x,mouse_y = -1;
  1491. static int mouse_last = 0;
  1492.  
  1493. #ifndef TK
  1494. int get_c()
  1495. {
  1496.     key_type c, first_key;
  1497.     int key_cnt, mc, n;
  1498.     register struct multi_key *mk, *multi_match;
  1499.     register int i;
  1500.  
  1501.     multi_match = NULL;
  1502.     first_key = 0;
  1503.     mouse_y = -1;
  1504.  
  1505.  next_key:
  1506.     if (s_hangup) return K_interrupt;
  1507.  
  1508.     if (do_macro_processing)
  1509.     switch (m_getc(&mc)) {
  1510.      case 0: break;
  1511.      case 1: return mc;
  1512.      case 2: return K_interrupt;
  1513.     }
  1514.  
  1515. #ifdef RESIZING
  1516.     if (s_resized) goto redraw;
  1517. #endif    /* RESIZING */
  1518.  
  1519.     if (batch_mode)
  1520.     nn_exitmsg(1, "Attempt to read keyboard input in batch mode");
  1521.  
  1522.     for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++)
  1523.     mk->cur_key = mk->keys;
  1524.     key_cnt = 0;
  1525.  
  1526. #ifdef FAKE_INTERRUPT
  1527.     if (setjmp(fake_keyb_sig)) goto intr;
  1528.     arm_fake_keyb_sig = 1;
  1529. #endif    /* FAKE_INTERRUPT */
  1530.  
  1531.  multi:
  1532.     switch (n = read_char_kbd(key_cnt)) {
  1533.  
  1534.      case RD_INTERRUPT:
  1535. #ifdef CBREAK
  1536.     if (s_redraw) goto redraw;
  1537. #endif    /* CBREAK */
  1538. #ifdef RESIZING
  1539.     if (s_resized) goto redraw;
  1540. #endif    /* RESIZING */
  1541.     goto intr;
  1542.  
  1543.      case RD_TIMEOUT:
  1544.     while (--key_cnt > 0) unread_char(multi_match->keys[key_cnt]);
  1545.     c = first_key;
  1546.     goto got_char;
  1547.     
  1548.      default:
  1549.     c = (key_type)n;
  1550.     if (data_bits < 8) c &= 0x7f;
  1551.     if (ignore_xon_xoff)
  1552.         if (c == CONTROL_('Q') || c == CONTROL_('S')) goto multi;
  1553.     break;
  1554.     }
  1555.  
  1556.     multi_match = NULL;
  1557.     for (i = multi_keys, mk = multi_key_list; --i >= 0; mk++) {
  1558.     if (mk->cur_key == NUL) continue;
  1559.     if (*(mk->cur_key)++ != c) {
  1560.         mk->cur_key = NUL;
  1561.         continue;
  1562.     }
  1563.     if (*(mk->cur_key) == NUL) {
  1564.         c = mk->code;
  1565.  
  1566.             /* xterm mouse specific code, translate cursor position
  1567.            into static variables, synthesize key up events */
  1568.         if ((c >= K_m_d1) && (c <= K_m_u1)) {
  1569.         mouse_x = read_char_kbd(key_cnt) - '!';
  1570.         mouse_y = read_char_kbd(key_cnt) - '!';
  1571.         if (c == K_m_u1) {
  1572.             if (mouse_last == K_m_d2) {
  1573.             c = K_m_u2;
  1574.             } else if (mouse_last == K_m_d3) {
  1575.             c = K_m_u3;
  1576.             }
  1577.         }
  1578.         mouse_last = c;
  1579.         }
  1580.         goto got_char;
  1581.     }
  1582.     multi_match = mk;
  1583.     }
  1584.  
  1585.     if (multi_match) {
  1586.     if (key_cnt == 0) first_key = c;
  1587.     key_cnt++;
  1588.     goto multi;
  1589.     }
  1590.     if (key_cnt) {
  1591.     if (key_cnt == 1 && first_key == 033) {
  1592.         unread_char(c);
  1593.         c = 033;
  1594.         goto got_char;
  1595.     }
  1596.     ding();
  1597.     flush_input();
  1598.     goto next_key;
  1599.     }
  1600.  
  1601.  got_char:
  1602. #ifdef FAKE_INTERRUPT
  1603.     arm_fake_keyb_sig = 0;
  1604. #endif    /* FAKE_INTERRUPT */
  1605.     c = global_key_map[c];
  1606.  
  1607. #ifndef CBREAK
  1608.     if (c == IntrC) return K_interrupt;    /* don't flush */
  1609.     if (c == SuspC) {
  1610.     if (enable_stop && suspend_nn()) goto redraw;
  1611.     goto next_key;
  1612.     }
  1613. #endif    /* CBREAK */
  1614.     return (int)c;
  1615.  
  1616.  intr:
  1617. #ifdef FAKE_INTERRUPT
  1618.     arm_fake_keyb_sig = 0;
  1619. #endif    /* FAKE_INTERRUPT */
  1620.     rd_count = 0;
  1621.     return K_interrupt;
  1622.  
  1623.  redraw:
  1624. #ifdef RESIZING
  1625.     s_resized = 0;
  1626. #endif    /* RESIZING */
  1627.     s_redraw = 0;
  1628.     return GETC_COMMAND | K_REDRAW;
  1629. }
  1630. #endif /* TK */
  1631.  
  1632.  
  1633. /*
  1634.  * read string with completion, pre-filling, and break on first char
  1635.  *
  1636.  *    dflt        is a string that will be use as default value if the
  1637.  *            space bar is hit as the first character.
  1638.  *
  1639.  *    prefill        pre-fill the buffer with .... and print it
  1640.  *
  1641.  *    break_chars    return immediately if one of these characters
  1642.  *            is entered as the first character.
  1643.  *
  1644.  *    completion     is a function that will fill the buffer with a value
  1645.  *            see the group_completion and file_completion routines
  1646.  *            for examples.
  1647.  */
  1648.  
  1649. char *get_s(dflt, prefill, break_chars, completion)
  1650. char *dflt, *prefill, *break_chars;
  1651. fct_type completion;
  1652. {
  1653.     static key_type lbuf[GET_S_BUFFER];
  1654.     register char *cp;
  1655.     int i, c, lastc;
  1656.     char *ret_val = (char *)lbuf;
  1657.     int comp_used, comp_len;
  1658.     int ostop, max, did_help;
  1659.     int hit_count;
  1660.  
  1661.     switch (m_gets((char *)lbuf)) {
  1662.      case 0:
  1663.     break;
  1664.      case 1:
  1665.     return (char *)lbuf;
  1666.      case 2:
  1667.     return NULL;
  1668.     }
  1669.  
  1670.     ostop = enable_stop;
  1671.     enable_stop = 0;
  1672.     do_macro_processing = 0;
  1673.     hit_count = 0;
  1674.  
  1675.     max = Columns - prompt_length;
  1676.  
  1677.     if (max >= FILENAME) max = FILENAME-1;
  1678.  
  1679.     i = comp_len = comp_used = did_help = 0;
  1680.  
  1681.     if (prefill && prefill[0]) {
  1682.     while ((c = *prefill++)) {
  1683.         if (i == max) break;
  1684.  
  1685.         tputc(c);
  1686.         lbuf[i] = c;
  1687.         i++;
  1688.     }
  1689.     fl;
  1690.     }
  1691.  
  1692.     if (dflt && *dflt == NUL)
  1693.     dflt = NULL;
  1694.  
  1695.     if (break_chars && *break_chars == NUL)
  1696.     break_chars = NULL;
  1697.  
  1698.     c = NUL;
  1699.     for(;;) {
  1700.     lastc = c;
  1701.     c = get_c();
  1702.     if (c & GETC_COMMAND) continue;
  1703.  
  1704.      kill_prefill_hack:
  1705.  
  1706.     hit_count++;
  1707.  
  1708.     if (i == 0) {
  1709.         if (c == comp1_key && dflt) {
  1710.         while ((c = *dflt++) != NUL && i < max) {
  1711.             tputc(c);
  1712.             lbuf[i] = c;
  1713.             i++;
  1714.         }
  1715.         fl;
  1716.         dflt = NULL;
  1717.         continue;
  1718.         }
  1719.         if ((cp = break_chars)) { /* Stupid ^@$# GCC!!! */
  1720.         while (*cp)
  1721.             if (*cp++ == c) {
  1722.             lbuf[0] = c;
  1723.             lbuf[1] = NUL;
  1724.             goto out;
  1725.             }
  1726.         }
  1727.     }
  1728.  
  1729.     if (completion != NULL_FCT) {
  1730.         if (comp_used && c == erase_key) {
  1731.         if (comp_len) {
  1732.             i -= comp_len;
  1733.             while (--comp_len >= 0) tputc(BS);
  1734.             clrline();
  1735.         }
  1736.         if (!CALL(completion)(lbuf, -(i+1)) && did_help)
  1737.             clrmsg(i);
  1738.         did_help = 0;
  1739.         comp_len = comp_used = 0;
  1740.         if (lastc == help_key) goto no_completion;
  1741.         continue;
  1742.         }
  1743.  
  1744.         if (c == comp1_key || c == comp2_key || c == help_key) {
  1745.         if (!comp_used || c == comp2_key ||
  1746.             (c == help_key && lastc != c)) {
  1747.             lbuf[i] = NUL;
  1748.             if ((comp_used = CALL(completion)(lbuf, i)) == 0) {
  1749.             ding();
  1750.             continue;
  1751.             }
  1752.             if (comp_used < 0) {
  1753.             comp_used = 0;
  1754.             goto no_completion;
  1755.             }
  1756.             comp_len = 0;
  1757.         }
  1758.         if (c == help_key) {
  1759.             if (CALL(completion)((char *)NULL, 1)) {
  1760.             gotoxy(prompt_length+i, prompt_line); fl;
  1761.             did_help = 1;
  1762.             }
  1763.             continue;
  1764.         }
  1765.  
  1766.         if (comp_len) {
  1767.             i -= comp_len;
  1768.             while (--comp_len >= 0) tputc(BS);
  1769.             clrline();
  1770.             comp_len = 0;
  1771.         }
  1772.  
  1773.         switch ( CALL(completion)((char *)NULL, 0) ) {
  1774.  
  1775.          case 0:    /* no possible completion */
  1776.             comp_used = 0;
  1777.             ding();
  1778.             continue;
  1779.  
  1780.          case 2:    /* whole new alternative */
  1781.             while (--i >= 0) tputc(BS);
  1782.             clrline();
  1783.  
  1784.             /*FALLTHRU*/
  1785.          case 1:    /* completion */
  1786.             comp_len = i;
  1787.             while ((c = lbuf[i])) {
  1788.             if (i == max) break;
  1789.             tputc(c);
  1790.             i++;
  1791.             }
  1792.             fl;
  1793.             comp_len = i - comp_len;
  1794.             continue;
  1795.         }
  1796.         }
  1797.  
  1798.         if (comp_used) {
  1799.         if (!CALL(completion)(lbuf, -(i+1)) && did_help)
  1800.             clrmsg(i);
  1801.         did_help = 0;
  1802.         comp_len = comp_used = 0;
  1803.         }
  1804.     }
  1805.  
  1806.      no_completion:
  1807.  
  1808.     if (c == CR || c == NL) {
  1809.         lbuf[i] = NUL;
  1810.         break;
  1811.     }
  1812.  
  1813.     if (c == erase_key) {
  1814.         if (i <= 0) continue;
  1815.         i--;
  1816.         tputc(BS);
  1817.         tputc(' ');
  1818.         tputc(BS);
  1819.         fl;
  1820.         continue;
  1821.     }
  1822.  
  1823.     if (c == delword_key) {
  1824.         if (i <= 0) continue;
  1825.         lbuf[i-1] = 'X';
  1826.         while (i > 0 && isalnum(lbuf[i-1])) { tputc(BS); i--; }
  1827.         clrline();
  1828.         continue;
  1829.     }
  1830.  
  1831.     if (c == kill_key) {
  1832.         while (i > 0) { tputc(BS); i--; }
  1833.         clrline();
  1834.         if (hit_count == 1 && dflt) {
  1835.         c = comp1_key;
  1836.         goto kill_prefill_hack;
  1837.         }
  1838.         continue;
  1839.     }
  1840.  
  1841.     if (c == K_interrupt) {
  1842.         ret_val = NULL;
  1843.         break;
  1844.     }
  1845.  
  1846.     if (data_bits == 8) {
  1847.         if (!iso8859(c)) continue;
  1848.     } else
  1849.     if (!isascii(c) || !isprint(c)) continue;
  1850.  
  1851.     if (i == max) continue;
  1852.  
  1853.     if (i > 0 && lbuf[i-1] == '/' && (c == '/' || c == '+')) {
  1854.         if (c != '/' || !guard_double_slash || (i > 1 && lbuf[i-2] == '/')) {
  1855.         if (completion == file_completion) {
  1856.             while (i > 0) { tputc(BS); i--; }
  1857.             clrline();
  1858.         }
  1859.         }
  1860.     }
  1861.  
  1862.     tputc(c);
  1863.     fl;
  1864.  
  1865.     lbuf[i] = c;
  1866.     i++;
  1867.     }
  1868.  out:
  1869.     enable_stop = ostop;
  1870.     do_macro_processing = 1;
  1871.     return ret_val;
  1872. }
  1873.  
  1874. export int list_offset = 0;
  1875.  
  1876. int list_completion(str)
  1877. char *str;
  1878. {
  1879.     static int cols, line;
  1880.  
  1881.     if (str == NULL) {
  1882.     cols = Columns;
  1883.     line = prompt_line + 1;
  1884.     if (line == Lines - 1) cols--;
  1885.  
  1886.     gotoxy(0, line);
  1887.     clrpage();
  1888.     return 1;
  1889.     }
  1890.  
  1891.     str += list_offset;
  1892.  
  1893.     for (;;) {
  1894.     cols -= strlen(str);
  1895.     if (cols >= 0) {
  1896.         tprintf("%s%s", str, cols > 0 ? " " : "");
  1897.         cols--;
  1898.         return 1;
  1899.     }
  1900.     if (line >= Lines - 1) return 0;
  1901.     line++;
  1902.     cols = Columns;
  1903.     gotoxy(0, line);
  1904.     if (line == Lines - 1) cols--;
  1905.     }
  1906. }
  1907.  
  1908. int yes(must_answer)
  1909. int must_answer;
  1910. {
  1911.     int c, help = 1, in_macro = 0;
  1912.  
  1913.     switch (m_yes()) {
  1914.      case 0:
  1915.     break;
  1916.      case 1:
  1917.     return 0;
  1918.      case 2:
  1919.     return 1;
  1920.      case 3:
  1921.     do_macro_processing = 0;
  1922.         in_macro++;
  1923.     break;
  1924.     }
  1925.     fl;
  1926.  
  1927.     for (;;) {
  1928.     if (!is_raw) {
  1929.         nn_raw();
  1930.         c = get_c();
  1931.         unset_raw();
  1932.     } else
  1933.         c = get_c();
  1934.  
  1935.     if (c == 'y' || c == 'Y') {
  1936.         c = 1;
  1937.         break;
  1938.     }
  1939.  
  1940.     if (must_answer == 0 && (c == SP || c == CR || c == NL)) {
  1941.         c = 1;
  1942.         break;
  1943.     }
  1944.  
  1945.     if (c == 'n' || c == 'N') {
  1946.         c = 0;
  1947.         break;
  1948.     }
  1949.     if (c == K_interrupt) {
  1950.         c = -1;
  1951.         break;
  1952.     }
  1953.     if (help) {
  1954.         tprintf(" y=YES n=NO"); fl;
  1955.         prompt_length += 11;
  1956.         help = 0;
  1957.     }
  1958.     }
  1959.  
  1960.     if (in_macro) {
  1961.     if (c < 0) m_break();
  1962.     do_macro_processing = 1;
  1963.     }
  1964.  
  1965.     tk("y_destroy");
  1966.     return c;
  1967. }
  1968.  
  1969. void 
  1970. ding()
  1971. {
  1972.     BATCH_CHECK_V;
  1973.  
  1974.     putp(bell_str);
  1975.     fl;
  1976. }
  1977.  
  1978.  
  1979. void display_file(name, modes)
  1980. char *name;
  1981. int modes;
  1982. {
  1983.     FILE *f;
  1984.     register c, stand_on;
  1985.     int linecnt, headln_cnt, hdline, no_conf;
  1986.     char headline[128];
  1987.     int cnt = 0;
  1988.  
  1989.     tkb_clear();
  1990.  
  1991.     headline[0] = 0;
  1992.     hdline = 0;
  1993.     no_conf = 0;
  1994.  
  1995.     headln_cnt = -1;
  1996.  
  1997.     if (modes & CLEAR_DISPLAY) {
  1998.     gotoxy(0,0);
  1999.     clrdisp();
  2000.     }
  2001.  
  2002. #ifdef TK
  2003.     linecnt = 500;
  2004. #else /* TK */
  2005.     linecnt = Lines - 1;
  2006. #endif /* TK */
  2007.  
  2008. chain:
  2009.  
  2010.     if (*name != '/') name = relative(help_directory, name);
  2011.     f = open_file(name, OPEN_READ);
  2012.     if (f == NULL) {
  2013.     ttprintf("\r\n\n");
  2014.     tprintf("File %s is not available", name);
  2015.     ttprintf("\n\n");
  2016.         if (!no_conf && (modes & CONFIRMATION))
  2017.           any_key(prompt_line);
  2018.     return;
  2019.     } else {
  2020.     stand_on = 0;
  2021.  
  2022.     if (!cnt)
  2023.             tk("display_Make");
  2024.     cnt++;
  2025.  
  2026.     while ((c = getc(f)) != EOF) {
  2027. #ifdef HAVE_JOBCONTROL
  2028.         if (s_redraw) {
  2029.         no_conf = 1;
  2030.         break;
  2031.         }
  2032. #endif    /* HAVE_JOBCONTROL */
  2033.         no_conf = 0;
  2034.         if (c == '\1') {
  2035.         tkb_c(1);
  2036.         if (STANDOUT) {
  2037.             putp(stand_on ? exit_standout_mode : enter_standout_mode);
  2038.             curxy_c += cookie_size;
  2039.             stand_on = !stand_on;
  2040.         }
  2041.         continue;
  2042.         }
  2043.         if (c == '\2') {
  2044.         headln_cnt = 0;
  2045.         continue;
  2046.         }
  2047.         if (c == '\3') {
  2048.         headln_cnt = 0;
  2049.         while ((c = getc(f)) != EOF && c != NL)
  2050.             headline[headln_cnt++] = c;
  2051.         headline[headln_cnt++] = NUL;
  2052.         name = headline;
  2053.         fclose(f);
  2054.         goto chain;
  2055.         }
  2056.         if (c == '\4') {
  2057.         tkb_tprintf("%s", version_id);
  2058.         continue;
  2059.         }
  2060.  
  2061.         if (headln_cnt >= 0)
  2062.         headline[headln_cnt++] = c;
  2063.  
  2064.         if (hdline) {
  2065.         tkb_tprintf("%s\r", headline);
  2066.         hdline = 0;
  2067.         linecnt--;
  2068.         }
  2069.  
  2070.         tkb_ttputc(c);
  2071.         if (c == NL) {
  2072.         ttputc(CR);
  2073.         tkb_c(0);
  2074.         tkb_display();
  2075.         if (headln_cnt >= 0) {
  2076.             headline[--headln_cnt] = 0;
  2077.             headln_cnt = -1;
  2078.         }
  2079.         if (--linecnt == 0) {
  2080.             no_conf = 1;
  2081.             if (any_key(0) == K_interrupt)
  2082.             break;
  2083.             linecnt = Lines - 1;
  2084.             if (modes & CLEAR_DISPLAY) {
  2085.             gotoxy(0,0);
  2086.             clrdisp();
  2087.             }
  2088.             hdline = headline[0];
  2089.         }
  2090.         }
  2091.     }
  2092.  
  2093.     if (stand_on) {
  2094.         putp(exit_standout_mode);
  2095.         curxy_c += cookie_size;
  2096.     }
  2097.     fclose(f);
  2098.     }
  2099.  
  2100.     prompt_line = Lines-1;    /* move prompt to last line */
  2101.  
  2102. #ifndef TK
  2103.     if (!no_conf && (modes & CONFIRMATION))
  2104.     any_key(prompt_line);
  2105. #endif /* TK */
  2106. }
  2107.  
  2108.  
  2109. /*VARARGS*/
  2110. void nn_exitmsg(va_alist)
  2111. va_dcl
  2112. {
  2113.     char *fmt;
  2114.     int n;
  2115.     use_vararg;
  2116.  
  2117.     if (terminal_speed != 0) {
  2118.     clrdisp();
  2119.     visual_off();
  2120.     }
  2121.  
  2122.     start_vararg;
  2123.     n = va_arg1(int);
  2124.     fmt = va_arg2(char *);
  2125.     vprintf(fmt, va_args3toN);
  2126.     putchar(NL);
  2127.     end_vararg;
  2128.  
  2129.     nn_exit(n);
  2130.     /*NOTREACHED*/
  2131. }
  2132.  
  2133. /*VARARGS*/
  2134. void msg(va_alist)
  2135. va_dcl
  2136. {
  2137.     use_vararg;
  2138.  
  2139.     start_vararg;
  2140.     vmsg(va_args1toN);
  2141. #ifdef TK
  2142.     tk("update");
  2143.     sleep(1);
  2144. #endif /* TK */
  2145.     end_vararg;
  2146. }
  2147.  
  2148. void push_msg(str)
  2149. char *str;
  2150. {
  2151.     register struct msg_list *mp, *newmsg;
  2152.     static int slots = 0;
  2153.     
  2154.     if (str != NULL) {
  2155.     if (slots > message_history) {
  2156.         for (mp = newmsg = msg_stack; mp->prev != NULL; mp = mp->prev)
  2157.         newmsg = mp;
  2158.         if (newmsg == mp)
  2159.         msg_stack = NULL;
  2160.         else {
  2161.         newmsg->prev = NULL;
  2162.         newmsg = mp;
  2163.         }
  2164.         freeobj(newmsg->buf);
  2165.     } else {
  2166.         slots++;
  2167.         newmsg = newobj(struct msg_list, 1);
  2168.     }
  2169.     newmsg->buf = copy_str(str);
  2170.     newmsg->prev = msg_stack;
  2171.     msg_stack = newmsg;
  2172.     }
  2173.     msg_ptr = msg_stack;
  2174. }
  2175.     
  2176. void vmsg(va_tail)
  2177. va_tdcl
  2178. {
  2179.     char *errmsg, *fmt;
  2180.     
  2181.     fmt = va_arg1(char *);
  2182.  
  2183.     if (fmt) {
  2184.     char lbuf[512];
  2185.     
  2186.     vsprintf(lbuf, fmt, va_args2toN);
  2187.     push_msg(lbuf);
  2188.     }
  2189.     
  2190.     if (msg_ptr) {
  2191.     errmsg = msg_ptr->buf;
  2192.     msg_ptr = msg_ptr->prev;
  2193.     } else {
  2194.     errmsg = "(no more messages)";
  2195.     msg_ptr = msg_stack;
  2196.     }
  2197.  
  2198.     if (terminal_speed == 0) {
  2199.     tprintf("%s\n", errmsg);
  2200.     fl;
  2201.     return;
  2202.     }
  2203.     
  2204.     gotoxy(0, Lines-1);
  2205.     tprintf("%s", errmsg);
  2206.     clrline();
  2207.     any_message = 1;
  2208.  
  2209.     if (prompt_line != Lines-1)
  2210.         gotoxy(prompt_length, prompt_line);
  2211.     fl;
  2212. }
  2213.  
  2214. void
  2215. clrmsg(col)
  2216. int col;
  2217. {
  2218.     BATCH_CHECK_V;
  2219.  
  2220.     gotoxy(0, prompt_line + 1);
  2221.     clrpage();
  2222.     if (col >= 0)
  2223.     gotoxy(prompt_length + col, prompt_line);
  2224.     fl;
  2225.     any_message = 0;
  2226. }
  2227.  
  2228.  
  2229. /*VARARGS*/
  2230. void
  2231. prompt(va_alist)
  2232. va_dcl
  2233. {
  2234.     register char *cp;
  2235.     int stand_on;
  2236.     char *fmt;
  2237.     static char cur_p[FILENAME];
  2238.     static char saved_p[FILENAME];
  2239.     use_vararg;
  2240.  
  2241.     prompt_clear();
  2242.     tkb_clear();
  2243.  
  2244.  
  2245.     BATCH_CHECK_V;
  2246.  
  2247.     start_vararg;
  2248.  
  2249.     fmt = va_arg1(char *);
  2250.  
  2251.     if (fmt == P_VERSION) {
  2252.     gotoxy(0, prompt_line + 1);
  2253.     tprintf("Release %s ", version_id);
  2254.     clrline();
  2255.     any_message++;
  2256.  
  2257.     if (prompt_line >= 0)
  2258.         gotoxy(prompt_length, prompt_line);
  2259.     goto out;
  2260.     }
  2261.  
  2262.     if (fmt == P_SAVE) {
  2263.     strcpy(saved_p, cur_p);
  2264.     goto out;
  2265.     }
  2266.  
  2267.     if (fmt == P_RESTORE)
  2268.     strcpy(cur_p, saved_p);
  2269.  
  2270.     if (prompt_line >= 0)
  2271.     gotoxy(0, prompt_line);
  2272.  
  2273.     if (fmt == P_MOVE) {
  2274.     clrline();
  2275.     goto out;
  2276.     }
  2277.  
  2278.     if (fmt != P_REDRAW && fmt != P_RESTORE)
  2279.     vsprintf(cur_p, fmt, va_args2toN);
  2280.  
  2281.     tputc(CR);
  2282.  
  2283.     for (cp = cur_p, stand_on = 0, prompt_length = 0; *cp; cp++) {
  2284.     if (*cp == '\1') {
  2285.         if (cp[1] != '\1') {
  2286.         if (STANDOUT) {
  2287.             stand_on = !stand_on;
  2288.             nn_standout(stand_on);
  2289.             prompt_length += cookie_size;
  2290.         }
  2291.         continue;
  2292.         }
  2293.         cp++;
  2294.     } else
  2295.     if (*cp == '\2') {
  2296.         time_t t;
  2297.         char   *timestr;
  2298.  
  2299.         t = tick_usage();
  2300.  
  2301.         if (show_current_time) {
  2302.         timestr = ctime(&t) + 11;
  2303.         timestr[5] = NUL;
  2304.  
  2305.         tkb_tprintf("-- %s ", timestr);
  2306.         prompt_length += 9;
  2307.         }
  2308.  
  2309.         if (unread_mail(t)) {
  2310.         tkb_tprintf("Mail ");
  2311.         prompt_length += 5;
  2312.         }
  2313.  
  2314.         continue;
  2315.     }
  2316.  
  2317.     tkb_ttputc(*cp);
  2318.     prompt_length ++;
  2319.     }
  2320.     if (stand_on) {
  2321.     nn_standout(0);
  2322.     prompt_length += cookie_size;
  2323.     }
  2324.  
  2325.     clrline();
  2326.     tkb_txt_a();
  2327.  
  2328.     if (fmt == P_RESTORE)
  2329.     restore_xy();
  2330. #if notdef
  2331.     else
  2332.     curxy_c = -1;
  2333. #endif
  2334.  
  2335.  out:
  2336.     end_vararg;
  2337.     tk_c_normal_prompt();
  2338. }
  2339.  
  2340.  
  2341. int any_key(line)
  2342. int line;
  2343. {
  2344.     int was_raw, c, dmp;
  2345.  
  2346.     BATCH_CHECK;
  2347.  
  2348.     was_raw = is_raw;
  2349.     if (!is_raw) nn_raw();
  2350.     if (line == 0)
  2351.     line = -1;
  2352.     else
  2353.     if (line < 0)
  2354.         line = Lines + line;
  2355.  
  2356.     if (line != 10000) {
  2357.     so_printxy(0, line, "Hit any key to continue");
  2358.     tk_txt_a("Hit any key to continue");
  2359.     }
  2360. #ifndef TK
  2361.     clrline();
  2362. #endif /* TK */
  2363.  
  2364.     dmp = do_macro_processing;
  2365.     do_macro_processing = 0;
  2366.     c = get_c();
  2367.     if (c == 'q' || c == 'Q') c = K_interrupt;
  2368.     do_macro_processing = dmp;
  2369.  
  2370.     if (!was_raw) unset_raw();
  2371.  
  2372.     return c;
  2373. }
  2374.  
  2375.  
  2376. static pg_fline, pg_width, pg_maxw, pg_line, pg_col, pg_quit;
  2377. export regexp *pg_regexp = NULL;
  2378. export int pg_new_regexp = 0;
  2379.  
  2380. void pg_init(first_line, cols)
  2381. int first_line, cols;
  2382. {
  2383.     if (pg_regexp) {
  2384.     freeobj(pg_regexp);
  2385.     pg_regexp = NULL;
  2386.     }
  2387.     pg_new_regexp = 0;
  2388.  
  2389.     pg_fline = first_line;
  2390.     pg_line = pg_fline - 1;
  2391.     pg_quit = pg_col = 0;
  2392.     pg_width = Columns / cols;
  2393.     pg_maxw = pg_width * (cols - 1);
  2394. }
  2395.  
  2396. int pg_scroll(n)
  2397. int n;
  2398. {
  2399. #ifndef TK
  2400.     pg_line += n;
  2401.     if (pg_line >= (Lines - 1)) {
  2402.     pg_line = 0;
  2403.     if (any_key(0) == K_interrupt)
  2404.         return 1;
  2405.     tputc(CR);
  2406.     clrline();
  2407.     }
  2408. #endif
  2409.     return 0;
  2410. }
  2411.  
  2412. int pg_next()
  2413. {
  2414.     int c;
  2415.  
  2416.     if (batch_mode) {
  2417.     putchar(NL);
  2418.     return 0;
  2419.     }
  2420.  
  2421. #ifndef TK
  2422.     pg_line++;
  2423.     if (pg_line < Lines) {
  2424.     gotoxy(pg_col, pg_line);
  2425.     if (pg_line == Lines - 1 && pg_col == pg_maxw) {
  2426.         c = any_key(0);
  2427.         if (c == '/') {
  2428.         char *expr;
  2429.         tputc(CR);
  2430.         tputc('/');
  2431.         clrline();
  2432.         expr = get_s((char *)NULL, (char *)NULL, (char *)NULL, NULL_FCT);
  2433.         if (expr != NULL && *expr != NUL) {
  2434.             freeobj(pg_regexp);
  2435.             pg_regexp = regcomp(expr);
  2436.             pg_new_regexp = 1;
  2437.         }
  2438.         }
  2439.         gotoxy(0, pg_fline);
  2440.         clrpage();
  2441.         pg_col = 0;
  2442.         pg_line = pg_fline;
  2443.         if (c == K_interrupt) {
  2444.         pg_quit = 1;
  2445.         return -1;
  2446.         }
  2447.         return 1;
  2448.     }
  2449.     } else {
  2450.     pg_line = pg_fline;
  2451.     pg_col += pg_width;
  2452.     gotoxy(pg_col, pg_line);
  2453.     }
  2454. #endif
  2455.     return 0;
  2456. }
  2457. void
  2458. pg_indent(pos)
  2459. int pos;
  2460. {
  2461.     int i;
  2462.  
  2463.     BATCH_CHECK_V;
  2464.  
  2465.     for (i=0; i<(pos - curxy_c + pg_col); i++)
  2466.     tkb_c(' ');
  2467.  
  2468.     gotoxy(pg_col + pos, pg_line);
  2469. }
  2470.  
  2471. int pg_end()
  2472. {
  2473. #ifndef TK
  2474.     int c;
  2475.  
  2476.     if (pg_quit == 0 && pg_next() == 0)
  2477.     c = any_key(0);
  2478.     else
  2479.     c = K_interrupt;
  2480.  
  2481.     if (pg_regexp) {
  2482.     freeobj(pg_regexp);
  2483.     pg_regexp = NULL;
  2484.     }
  2485.  
  2486.     return c == K_interrupt ? -1 : 0;
  2487. #else
  2488.     return 0;
  2489. #endif
  2490. }
  2491.  
  2492. void
  2493. user_delay(ticks)
  2494. int ticks;
  2495. {
  2496.     BATCH_CHECK_V;
  2497.  
  2498.     if (ticks <= 0 || conf_dont_sleep) {
  2499.     tprintf(" <>");
  2500.     any_key(10000);
  2501.     } else {
  2502.     fl;
  2503.     sleep((unsigned)ticks);
  2504.     }
  2505. }
  2506.  
  2507.